import axios from "axios";
import {isOk} from "@/lib/constant";
import {getAccessToken} from "@/lib/tokenUtil";
import {headerName} from "@/lib/constant";
import {Loading} from "element-ui";
import {refreshToken} from "@/api/system";



//进行后端请求时，显示loading
function addLoading() {
    let option = {
        fullscreen:true,
        lock:true,
        text:"loading...",
        background: 'rgba(0, 0, 0, 0.7)'
    }
    let loading = Loading.service(option);
    return loading;
}

//关闭loading
function hideLoading(loadingInstance) {
    loadingInstance.close();
}

class HttpRequest {
    //构造函数
    constructor(baseUrl) {
        this.baseUrl = baseUrl
    }

    //针对axios实例的默认配置
    initConfig() {
        const config = {
            baseURL: this.baseUrl,
            headers: {
                //
            }
        }
        return config
    }

    //创建并返回axios实例，options参数为创建实例时传递的个性化参数
    request(options) {
        const instance = axios.create()
        //将默认配置与个性化配置整合。
        //如果二者发生冲突，个性化配置options，覆盖初始化默认配置initConfig()
        options = Object.assign(this.initConfig(), options)
        let loadingInstance = null;
        //配置请求时的拦截器
        instance.interceptors.request.use(config =>{
            loadingInstance = addLoading();
            const token = getAccessToken();
            //每次请求时，带上jwt信息
            if(!!token){
                config.headers[headerName] = token;
            }
            return config;
        },
            error => {
                return Promise.reject(error)
            }
            )
        //配置返回时的拦截器信息
        instance.interceptors.response.use(
            // 成功调用时的操作
            resp => {
                hideLoading(loadingInstance);
                //获取返回的数据结果
                const res = resp.data;
                if (!isOk(res)) {
                    //服务器处理失败，当作异常返回
                    return Promise.reject(res);
                } else {
                    return res;
                }
            },
            error => {
                hideLoading(loadingInstance);
                if (error && error.response) {
                    //处理认证失败的情况
                    if(error.response.status==401){
                        //判断是否存在token，如果没有，说明是没有登录
                        let access_token = getAccessToken();
                        if(!!access_token){
                            //返回promise信息，直接返回到请求所在页面自己处理
                            let resp = refreshTokenAndReRequest(error)
                            return resp
                        }
                        return Promise.reject(error)
                }else{
                        //处理其他情况
                        switch (error.response.status) {
                            case 400:
                                error.message = '错误请求';
                                break;
                            case 403:
                                error.message = '拒绝访问';
                                break;
                            case 404:
                                error.message = '请求错误,未找到该资源';
                                break;
                            case 405:
                                error.message = '请求方法未允许';
                                break;
                            case 408:
                                error.message = '请求超时';
                                break;
                            case 500:
                                error.message = '服务器端出错';
                                break;
                            case 501:
                                error.message = '网络未实现';
                                break;
                            case 502:
                                error.message = '网络错误';
                                break;
                            case 503:
                                error.message = '服务不可用';
                                break;
                            case 504:
                                error.message = '网络超时';
                                break;
                            case 505:
                                error.message = 'http版本不支持该请求';
                                break;
                            default:
                                error.message = `未知错误${error.response.status}`;
                        }
                        return Promise.reject(error)
                    }
                }else{
                    error.message = "连接到服务器失败！"
                    return Promise.reject(error);
                }
            }
        )
        //在这里可以为axios实例instance设置拦截器
        return instance(options)
    }
}
/*
1.重新请求token
2.重新请求失败的数据
* */
async function  refreshTokenAndReRequest(error){
    console.log("access_token过期，重新请求")
    await refreshToken();
    console.log("access_token刷新成功")
    console.log("重新请求数据")
    let result = await requestFailData(error)
    console.log("重新请求数据成功")
    return result;
}
function requestFailData(error) {
        return new Promise((resolve, reject)=> {
            //重新发送请求
            let config = error.response.config
            config.headers[headerName]=getAccessToken();//获取新的token
            axios.request(config)
                .then(resp => {
                    //获取返回的数据结果
                    const res = resp.data;
                    if (!isOk(res)) {
                        //服务器处理失败，当作异常返回
                        reject(res);
                    } else {
                        resolve(resp.data);
                    }
                }).catch(err => {
                     reject(err)
                })
    })
}


export default HttpRequest;